//日志头文件
#ifndef __SYLAR_LOG_H__
#define __SYLAR_LOG_H__
#include <string>
#include <stdint.h>
#include <memory>
#include <list>
#include <sstream>
#include <fstream>
#include <vector>
#include <stdarg.h>
#include <map>
#include <time.h>
#include "singleton.h"
#include "util.h"
#include "thread.h"

/**
 * @brief 使用流式方式将日志级别level的日志写入到logger
 */
#define SYLAR_LOG_LEVEL(logger, level) \
    if(logger->getLevel() <= level) \
        sylar::LogEventWrap(sylar::LogEvent::ptr(new sylar::LogEvent(logger, level, \
                        __FILE__, __LINE__, 0, sylar::GetThreadId(),\
                sylar::GetFiberId(), time(0), sylar::Thread::GetName()))).getSS()
/**
 * @brief 使用流式方式将日志级别debug的日志写入到logger
 */
#define SYLAR_LOG_DEBUG(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::DEBUG)
#define SYLAR_LOG_INFO(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::INFO)
#define SYLAR_LOG_WARN(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::WARN)
#define SYLAR_LOG_ERROR(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::ERROR)
#define SYLAR_LOG_FATAL(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::FATAL)

/**
 * @brief 使用格式化方式将日志级别level的日志写入到logger
 */
#define SYLAR_LOG_FMT_LEVEL(logger, level, fmt, ...) \
    if(logger->getLevel() <= level) \
        sylar::LogEventWrap(sylar::LogEvent::ptr(new sylar::LogEvent(logger, level, \
                        __FILE__, __LINE__, 0, sylar::GetThreadId(),\
                sylar::GetFiberId(), time(0), sylar::Thread::GetName()))).getEvent()->format(fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_DEBUG(logger, fmt, ...) SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::DEBUG, fmt, __VA_ARGS__)
#define SYLAR_LOG_FMT_INFO(logger, fmt, ...)  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::INFO, fmt, __VA_ARGS__)
#define SYLAR_LOG_FMT_WARN(logger, fmt, ...)  SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::WARN, fmt, __VA_ARGS__)
#define SYLAR_LOG_FMT_ERROR(logger, fmt, ...) SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::ERROR, fmt, __VA_ARGS__)
#define SYLAR_LOG_FMT_FATAL(logger, fmt, ...) SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::FATAL, fmt, __VA_ARGS__)
 
#define SYLAR_LOG_ROOT  sylar::LoggerMgr::GetInstance()->getRoot
#define SYLAR_LOG_NAME(name) sylar::LoggerMgr::GetInstance()->getLogger(name)

namespace sylar{

/**
 * @brief 日志级别
**/
class LogLevel{
public:
	enum Level{
		UNKNOW = 0,
		DEBUG = 1,
		INFO = 2,
		WARN = 3,
		ERROR = 4,
		FATAL = 5
	};
	static const char *ToString(Level level);
	static LogLevel::Level FromString(const std::string& str);

};

class Logger;
class LoggerManager;

/**
 * @brief 日志事件
**/
class LogEvent{
public:
	typedef std::shared_ptr<LogEvent> ptr;
	LogEvent(std::shared_ptr<Logger> logger, LogLevel::Level level
			, const char* file, int32_t line, uint32_t elapse
			, uint32_t threadId, uint32_t fiberId, uint64_t time, const std::string& threadName);

	const char* getFile() const {return m_file;}
	int32_t getLine() const {return m_line;}
	uint32_t getElapse() const {return m_elapse;}
	uint32_t getThreadId() const {return m_threadId;}
	uint32_t getFiberId() const {return m_fiberId;}
	uint64_t getTime() const {return m_time;}
	std::string getContent() const {return m_ss.str();}
	std::stringstream& getSS() {return m_ss;}
	std::shared_ptr<Logger> getLogger() {return m_logger;}
	LogLevel::Level getLevel(){return m_level;}
	std::string& getThreadName(){return m_threadName;}

	void format(const char* fmt, ...);
	void format(const char* fmt, va_list al);

private:
	const char *m_file = nullptr;		//文件名
	int32_t m_line;						//行号
	uint32_t m_elapse;					//程序启动开始到现在的毫秒数
	uint32_t m_threadId;				//线程id
	uint32_t m_fiberId;					//协程id
	uint64_t m_time;					//时间戳
	std::stringstream m_ss;				//内容文本
	std::shared_ptr<Logger> m_logger; 	//所属的日志器
	LogLevel::Level m_level;			//日志等级
	std::string m_threadName;			//线程名称
};

/**
 * @brief 日志时间包: 将日志事件打包到其中, 在析构函数中输出
 */  

class LogEventWrap{
public:
	LogEventWrap(LogEvent::ptr event);
	~LogEventWrap();
	std::stringstream& getSS();
	LogEvent::ptr getEvent() const { return m_event;}
private: 
	LogEvent::ptr m_event;
};

/**
 * @brief 日志格式器 : 
 */
class LogFormatter{
public:
	typedef std::shared_ptr<LogFormatter> ptr;
	
	LogFormatter(const std::string &pattern);
	std::string format(std::shared_ptr<Logger> logger, LogLevel::Level levle, LogEvent::ptr event);
public:
	/**
	 * @brief 具体的格式item
	 */
	class FormatItem{
	public:
		typedef std::shared_ptr<FormatItem> ptr;
		//FormatItem(const std::string& fmt = ""){}
		virtual ~FormatItem(){}
		virtual void format(std::ostream& os, std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) = 0;
	};

	void init();
	bool isError() const {return m_error;}
	const std::string getPattern() const {return m_pattern;}
private:
	std::string m_pattern;				//日志格式
	std::vector<FormatItem::ptr> m_items;	//解析格式后的FormatItem
	bool m_error = false;				//记录pattern string 是否存在错误
};

/**
 * @brief 日志输出地
 */
class LogAppender{
friend class Logger;
public:
	typedef std::shared_ptr<LogAppender> ptr;
	typedef Spinlock MutexType;

	virtual ~LogAppender(){}
	virtual void log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) = 0;
	virtual std::string toYamlString() = 0;
	
	LogFormatter::ptr getFormatter();
	void setFormatter(LogFormatter::ptr val);

	LogLevel::Level getLevel() const { return m_level;}
	void setLevel(LogLevel::Level val) { m_level = val;}
	
protected:
	LogLevel::Level m_level = LogLevel::DEBUG;
	bool m_hasFormatter = false;
	MutexType m_mutex;
	LogFormatter::ptr m_formatter;
};

/**
 * @brief 日志输出地 -> 标准输出
 */
class StdoutLogAppender : public LogAppender{
public: 
	typedef std::shared_ptr<StdoutLogAppender> ptr;
	virtual void log(std::shared_ptr<Logger> logger, LogLevel::Level, LogEvent::ptr event) override;
	virtual std::string toYamlString() override;
};

/**
 * @brief 日志输出地 -> 文件输出
 */
class FileLogAppender : public LogAppender{
public:
	typedef std::shared_ptr<FileLogAppender> ptr;
	FileLogAppender(const std::string& filename);
	virtual void log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) override;
	virtual std::string toYamlString() override;
	bool reopen();

private:
	std::string m_filename;
	std::ofstream m_filestream;
	uint64_t m_lastTime = 0;	//
};


/**
 * @brief 日志器
 */
class Logger : public std::enable_shared_from_this<Logger> { 
	friend class LoggerManager;

public:
	typedef std::shared_ptr<Logger> ptr;
	typedef Spinlock MutexType;

	Logger(std::string name = "root");
	void log(LogLevel::Level level, LogEvent::ptr event);
	
	void debug(LogEvent::ptr event);
	void info(LogEvent::ptr event);
	void warn(LogEvent::ptr event);
	void error(LogEvent::ptr event);
	void fatal(LogEvent::ptr event);

	void addAppender(LogAppender::ptr appender);
	void delAppender(LogAppender::ptr appender);
	void clearAppenders();

	LogLevel::Level getLevel() const {return m_level;}
	void setLevel(LogLevel::Level val) {m_level = val;}
	const std::string& getName() const {return m_name;}
	void setFormatter(LogFormatter::ptr val);
	void setFormatter(const std::string& val);

	LogFormatter::ptr getFormatter();

	std::string toYamlString();

private:
	MutexType m_mutex;
	std::string m_name;			//日志名称
	LogLevel::Level m_level;	//日志级别
	std::list<LogAppender::ptr> m_appenders;	//Appender集合
	LogFormatter::ptr m_formatter;	//日志的输出格式
	Logger::ptr m_root;			//若日志器中不存在appender, 则输出到m_root
};

/**
 * @brief 日志的统一管理器
 */
class LoggerManager{
public:
	typedef Spinlock MutexType;
	LoggerManager();
	Logger::ptr getLogger(const std::string &name);
	Logger::ptr getRoot() {return m_root;}

	std::string toYamlString();
	void init();
private:
	MutexType m_mutex;
	std::map<std::string, Logger::ptr> m_loggers;	//日志器
	Logger::ptr m_root;								//默认日志器
};

/**
 * @brief 日志管理器的单例
 */
typedef sylar::Singleton<LoggerManager> LoggerMgr;
} // namespace sylar

#endif